package com.mazecore.game;

import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.Light;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.ui.Picture;
import de.lessvoid.nifty.Nifty;
import java.util.ArrayList;

public class Application extends SimpleApplication {

    boolean[][] wall;
    Geometry geomBox;
    SpotLight spot;
    int health = 100 * 1000;
    int startH = 1;
    int healthc = 100 * 1000;
    int fakel = 10;
    TerrainQuad terrain;
    Material terMaterial;
    private boolean gamenow;

    public int w(int w) {
        return (int) ((float) settings.getWidth() / 1000 * w);
    }

    public int h(int h) {
        return (int) ((float) settings.getHeight() / 1000 * h);
    }
    Picture picHealth;
    BitmapText fakelText;
 public Nifty nifty;
ArrayList<Light> ligs = new ArrayList<Light>();
    @Override
    public void simpleInitApp() {
        
  inputManager.addMapping("Shoot",
                new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar
                new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // trigger 2: left-button click
        inputManager.addListener(actionListener, "Shoot");
     
        NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager,
                                                          inputManager,
                                                          audioRenderer,
                                                          guiViewPort);
        nifty = niftyDisplay.getNifty();
        nifty.fromXml("Interface/menu.xml", "main_menu");

        // attach the nifty display to the gui view port as a processor
        guiViewPort.addProcessor(niftyDisplay);

        // disable the fly cam
        flyCam.setEnabled(false);
      //  flyCam.setDragToRotate(true);
        inputManager.setCursorVisible(true);
 
         
        
       
    }

    public void startGame(int size) {
        health = 100 * 1000;
nifty.exit();fakel = 10;
  flyCam.setEnabled(true);
   inputManager.setCursorVisible(false);
        rootNode.detachAllChildren();
 
         a=this;
   
         flyCam.setEnabled(true);
         flyCam.setMoveSpeed(40);
               
        cam.setLocation(new Vector3f(-20, 5, -20));
        
        cam.setFrustumFar(300);

        spot = new SpotLight();
        spot.setSpotRange(300f);
        spot.setSpotInnerAngle(10f * FastMath.DEG_TO_RAD);
        spot.setSpotOuterAngle(25f * FastMath.DEG_TO_RAD);
        spot.setColor(ColorRGBA.White.mult(1.3f));
        ligs.add(spot);
        Picture pic = new Picture("HUD Picture");
        pic.setImage(assetManager, "Textures/fakel.png", true);
        pic.setWidth(w(40));
        pic.setHeight(h(160));
        pic.setPosition(w(200), h(50));
           
        guiNode.attachChild(pic);
   
        pic = new Picture("HUD Picture");
        pic.setImage(assetManager, "Textures/h.png", true);
        pic.setWidth(w(300));
        pic.setHeight(h(30));
        pic.setPosition(w(650), h(55));
        picHealth = pic;
        guiNode.attachChild(pic);
        pic = new Picture("HUD Picture");
        pic.setImage(assetManager, "Textures/hr.png", true);
        pic.setWidth(w(320));
        pic.setHeight(h(40));
        pic.setPosition(w(640), h(50));
        guiNode.attachChild(pic);
        BitmapText hudText = new BitmapText(guiFont, false);
        hudText.setSize(guiFont.getCharSet().getRenderedSize());
        hudText.setColor(ColorRGBA.Red);
       hudText.setText(fakel+"");

        hudText.setLocalTranslation(w(250), h(100), 0);
        guiNode.attachChild(hudText);
        fakelText = hudText;

        rootNode.addLight(spot);
        
        terMaterial = new Material(assetManager, 
            "Common/MatDefs/Terrain/Terrain.j3md");
        int patchSize = 65;

  /*  Texture dirt = assetManager.loadTexture(
            "Textures/dirt.jpg");
    dirt.setWrap(Texture.WrapMode.Repeat);
    terMaterial.setTexture("Tex2", dirt);
    terMaterial.setFloat("Tex2Scale", 32f);
    terrain = new TerrainQuad("my terrain", patchSize, 513,
            new float[512]);
    terrain.setMaterial(terMaterial);
    terrain.setLocalTranslation(0, 0, 0);
    terrain.setLocalScale(2f, 1f, 2f);
    rootNode.attachChild(terrain);*/
        initAudio();
      
        wall = new boolean[size + 1][size + 1];

        MazeGenerator maze = new MazeGenerator(size, size, 98);
        maze.generateWalls();
        //maze.display();
        for (int i = 0; i < size + 1; i++) {
            for (int j = 0; j < size + 1; j++) {
                if (maze.getMaze()[i * (size + 1) + j] == 1) {
                    wall[i][j] = true;

                    createWall(i, j);
                } else {
                    wall[i][j] = false;
                }
            }
        }
        for (int i = 0; i < (size + 1) * 2; i += 4) {
            for (int j = 0; j < (size + 1) * 2; j += 4) {
                createBox(new Vector3f(4, 1, 4), new Vector3f(i, 0, j),"Textures/dirt.jpg");
                createBox(new Vector3f(4, 1, 4), new Vector3f(i, 4, j),"Textures/1221.jpg");
            }
        }
        
        for (int i = -30; i < 0; i += 4) {
            for (int j = 0; j < (size + 1) * 2; j += 4) {
                createBox(new Vector3f(4, 1, 4), new Vector3f(i-2, 0, j),"Textures/dirt.jpg");
               
            }
        }


        cam.setLocation(new Vector3f(size * 20 - 20, 20, size * 20 - 20));

gamenow=true;


    }

    public void createWall(int x, int y) {


        createBox(new Vector3f(2, 5, 2), new Vector3f(x * 2, 1.5f, y * 2));

    }

    public void createBox(Vector3f size, Vector3f pos) {

        Box b = new Box(pos.mult(10), size.x * 5, size.y * 5, size.z * 5);
        Geometry geom = new Geometry("Box", b);
        Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
        mat.setTexture("DiffuseMap", assetManager.loadTexture("Textures/BrickWall.jpg"));
        mat.setTexture("NormalMap", assetManager.loadTexture("Textures/BrickWall_normal.jpg"));
        mat.setBoolean("UseMaterialColors", true);
        mat.setColor("Specular", ColorRGBA.White);
        mat.setColor("Diffuse", ColorRGBA.White);
        mat.setFloat("Shininess", 1f);

        geom.setMaterial(mat);
        rootNode.attachChild(geom);

    }
    
    public void createBox(Vector3f size, Vector3f pos, String diffuseMap) {

        Box b = new Box(pos.mult(10), size.x * 5, size.y * 5, size.z * 5);
        Geometry geom = new Geometry("Box", b);
        Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

        mat.setTexture("DiffuseMap", assetManager.loadTexture(diffuseMap));
        
        mat.setBoolean("UseMaterialColors", true);
        mat.setColor("Specular", ColorRGBA.White);
        mat.setColor("Diffuse", ColorRGBA.White);
        mat.setFloat("Shininess", 1f);

        geom.setMaterial(mat);
        rootNode.attachChild(geom);

    }
    
    
float xold=0;
float yold=0;
    @Override
    public void update() {
        super.update();
        if(gamenow){
          
        health -= timer.getTimePerFrame() * speed * 3;
        
        if(health==0) {
                endGameLose();
            }
        int h = health / (1000/startH);
        picHealth.setWidth(w(300) * (float) h / 100);

        Vector3f location = cam.getLocation();
        
        if(Math.abs(xold-location.x)>0.01f || Math.abs(yold-location.z)>0.01f){
            audio_gun.play();
        }
        
        xold=location.x;
        yold=location.z;
        int x = (int) Math.floor((location.x + 10) / 20);
        int y = (int) Math.floor((location.z + 10) / 20);
        if(x<0) {
        endGame();
        }
        int x1 = (int) Math.floor((location.x + 10 + 2) / 20);
        int x2 = (int) Math.floor((location.x + 10 - 2) / 20);
        int y1 = (int) Math.floor((location.z + 10 + 2) / 20);
        int y2 = (int) Math.floor((location.z + 10 - 2) / 20);
        if (x1 >= 0 && y >= 0 && x1 < wall.length && y < wall.length) {
            if (wall[x1][y]) {
                cam.setLocation(new Vector3f((x + 1) * 20 - 10 - 2, location.y, location.z));
            }
        }
        if (x2 >= 0 && y >= 0 && x2 < wall.length && y < wall.length) {
            if (wall[x2][y]) {
                cam.setLocation(new Vector3f((x) * 20 - 10 + 2, location.y, location.z));
            }
        }
        if (x >= 0 && y1 >= 0 && x < wall.length && y1 < wall.length) {
            if (wall[x][y1]) {
                cam.setLocation(new Vector3f(location.x, location.y, (y + 1) * 20 - 10 - 2));
            }
        }
        if (x >= 0 && y2 >= 0 && x < wall.length && y2 < wall.length) {
            if (wall[x][y2]) {
                cam.setLocation(new Vector3f(location.x, location.y, (y) * 20 - 10 + 2));
            }
        }

        cam.setLocation(new Vector3f(location.x, 20, location.z));

        spot.setPosition(cam.getLocation().add(new Vector3f(0, -1, 0)));
        spot.setDirection(cam.getDirection());
        }
    }
    public static Application a;
    Geometry mark;
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
            try {
                if(health+10<healthc){
                if (name.equals("Shoot") && !keyPressed) {
                    // 1. Reset results list.
                    CollisionResults results = new CollisionResults();
                    // 2. Aim the ray from cam loc to cam direction.
                    Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                    // 3. Collect intersections between Ray and Shootables in results list.
                    rootNode.collideWith(ray, results);
                    // 4. Print the results
                    
                    for (int i = 0; i < results.size(); i++) {
                        // For each hit, we know distance, impact point, name of geometry.
                        float dist = results.getCollision(i).getDistance();
                        Vector3f pt = results.getCollision(i).getContactPoint();
                        String hit = results.getCollision(i).getGeometry().getName();
                        if (pt.getY() > 4.0f && pt.getY() < 6.0f && i == 0) {
                            if(fakel>0){
                                fakel--;
                                fakelText.setText(fakel+"");
                            createTorch(pt.x, pt.z);
                            }
                        }
                    }
                    // 5. Use the results (we mark the hit object)
                    if (results.size() > 0) {
                        // The closest collision point is what was truly hit:
                        CollisionResult closest = results.getClosestCollision();
                        // Let's interact - we mark the hit with a red dot.
                        mark.setLocalTranslation(closest.getContactPoint());
                        rootNode.attachChild(mark);
                    } else {
                        // No hits? Then remove the red mark.
                        rootNode.detachChild(mark);
                    }
                }
                }
            } catch (Exception e) {
            }
        }

        
    };
       

    private void createTorch(float x, float z) {
         Box b = new Box(new Vector3f(x,7f,z), 0.5f, 4, 0.5f);
        Geometry geom = new Geometry("Box", b);
        Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

        mat.setTexture("DiffuseMap", assetManager.loadTexture("Textures/00.jpg"));
        
        mat.setBoolean("UseMaterialColors", true);
        mat.setColor("Specular", ColorRGBA.White);
        mat.setColor("Diffuse", ColorRGBA.White);
        mat.setFloat("Shininess", 1f);

        geom.setMaterial(mat);
        rootNode.attachChild(geom);
        
         b = new Box(new Vector3f(x,11.5f,z), 0.5f, 0.5f, 0.5f);
         geom = new Geometry("Box", b);
         mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

        mat.setColor("Color", ColorRGBA.Yellow);
       

        geom.setMaterial(mat);
        rootNode.attachChild(geom);
        
        PointLight lamp_light = new PointLight();
        lamp_light.setColor(ColorRGBA.Yellow);
        lamp_light.setRadius(40f);
        //System.out.println();
        lamp_light.setPosition(b.getCenter());
        rootNode.addLight(lamp_light);
        ligs.add(lamp_light);
        
    }
   private AudioNode audio_gun;
  private AudioNode audio_nature; 
     /** We create two audio nodes. */
  private void initAudio() {
    /* gun shot sound is to be triggered by a mouse click. */
    audio_gun = new AudioNode(assetManager, "Sounds/2.ogg", false);
    audio_gun.setLooping(false);
    audio_gun.setVolume(2);
    rootNode.attachChild(audio_gun);
    /* nature sound - keeps playing in a loop. */
    audio_nature = new AudioNode(assetManager, "Sounds/1.ogg", false);
    audio_nature.setLooping(true);  // activate continuous playing
    audio_nature.setPositional(true);
    audio_nature.setLocalTranslation(Vector3f.ZERO.clone());
    audio_nature.setVolume(2);
    rootNode.attachChild(audio_nature);
    audio_nature.play(); // play continuously!
  }

    private void endGame() {
        
        gamenow = false;
         for(Light l: ligs){
            rootNode.removeLight(l);
        }
        ligs = new ArrayList<Light>();
        rootNode.detachAllChildren();
        guiNode.detachAllChildren();
        audio_nature.stop();
         nifty.fromXml("Interface/menu.xml", "win");
        flyCam.setEnabled(false);
   inputManager.setCursorVisible(true);
    }

    private void endGameLose() {
      
        gamenow = false;
        for(Light l: ligs){
           rootNode.removeLight(l);
        }
        ligs = new ArrayList<Light>();
        rootNode.detachAllChildren();
             guiNode.detachAllChildren();
        audio_nature.stop();
         nifty.fromXml("Interface/menu.xml", "lose");
        flyCam.setEnabled(false);
   inputManager.setCursorVisible(true);
   
    }
   
    
   
    
    
}
